package org.hit.burkun.network.tester;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.Map.Entry;

import org.hit.burkun.file.FileHelper;
import org.hit.burkun.network.EdgeInfo;
import org.hit.burkun.network.SerializableGraph;
import org.hit.burkun.network.Vertex;
import org.hit.burkun.network.models.RandomWalkWithRestart;
import org.hit.burkun.network.models.SimplePageRank.VertexWithPr;
import org.hit.burkun.umls.relation.UniformRelation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RandomWalkWithRestartMethods {
	public static void main(String[] args) {
		 HashMap<String, HashSet<EdgeInfo>> testTrue =
		 ValidData.readTestTrueObj();
		 //用训练集找alpha
		 HashMap<String, HashSet<EdgeInfo>> validFalse =
		 ValidData.readTestFalseTrainObj();
		 HashMap<String, HashSet<EdgeInfo>> validTrue =
				 ValidData.readTestTrueTrainObj();
		 SerializableGraph sg = ValidData.getRemovedSg(false, testTrue);
//		 //---extend do id
//		 //sg = GraphFeatures.getBubbledGeneGraph(sg,Entity.TYPE.DISEASE_ONTOLOGY,UniformRelation.TYPE.DO_IS_A, 3, 0.1);
//		// do_is_a, hp_is_a, go_*, do_gene, go_gene, hp_gene, gene_gene
		 UniformRelation.weights[0] = 1;
		 UniformRelation.weights[1] = 1;
		 UniformRelation.weights[2] = 1;
		 UniformRelation.weights[3] = 1;
		 UniformRelation.weights[4] = 1;
		 UniformRelation.weights[5] = 1;
		 UniformRelation.weights[6] = 1;
		 double alpha = 0.1;
		 for(int i=0; i<9; i++){
			 HashMap<String, LinkedList<VertexWithPr>> mapRes = getAllPr(testTrue,
			 sg, true, false, alpha); //dir no two way 加快进度
			 writeFinallResToFile(validTrue, validFalse, mapRes, false, "data/dir-pr2-nodir-wight-1.0-a-"+alpha + ".txt");
			 alpha += 0.1;
		 }
//----------------------------------------------------------		
//		HashMap<String, HashSet<EdgeInfo>> testTrue = ValidData
//				.readTestTrueObj();
//		HashMap<String, HashSet<EdgeInfo>> testFalseValid = ValidData
//				.readTestFalseValidObj();
//		HashMap<String, HashSet<EdgeInfo>> testTrueValid = ValidData
//				.readTestTrueValidObj();
//		SerializableGraph sg = ValidData.getRemovedSg(false, testTrue);
//		testDifferentWeightDo(sg, testTrueValid, testFalseValid);
//		testDifferentWeightHp(sg, testTrueValid, testFalseValid);
//		testDifferentWeightGo(sg, testTrueValid, testFalseValid);
//		testDifferentWeightString(sg, testTrueValid, testFalseValid);
	}

	public static void testDifferentWeightDo(SerializableGraph sg, HashMap<String, HashSet<EdgeInfo>> testTrue , HashMap<String, HashSet<EdgeInfo>> testFalse, double alpha) {
		// do_is_a, hp_is_a, go_*, do_gene, go_gene, hp_gene, gene_gene
		double curWeight = 0;
		int curIdx = 0;
		boolean useTwoWay = false;
		for (int i = 0; i < 2; i++) {
			curWeight = 0;
			for (int j = 0; j < 30; j++) {
				UniformRelation.weights[curIdx] = curWeight;
				HashMap<String, LinkedList<VertexWithPr>> mapRes = getAllPr(
						testTrue, sg, true, useTwoWay, alpha);
				writeFinallResToFile(testTrue, testFalse, mapRes, useTwoWay,
						"data/handweight/pr2-do-" + curIdx + "-" + curWeight + ".txt");
				curWeight += 0.2;
			}
			UniformRelation.weights[curIdx] = 1;
			curIdx += 3;
		}
	}

	public static void testDifferentWeightGo(SerializableGraph sg, HashMap<String, HashSet<EdgeInfo>> testTrue , HashMap<String, HashSet<EdgeInfo>> testFalse, double alpha) {
		// do_is_a, hp_is_a, go_*, do_gene, go_gene, hp_gene, gene_gene
		double curWeight = 0;
//		int curIdx = 2;
		int curIdx = 4;
		boolean useTwoWay = false;
//		for (int i = 0; i < 2; i++) {
		for(int i=0; i<1; i++){
			curWeight = 0;
			for (int j = 0; j < 30; j++) {
				UniformRelation.weights[curIdx] = curWeight;
				HashMap<String, LinkedList<VertexWithPr>> mapRes = getAllPr(
						testTrue, sg, true, useTwoWay, alpha);
				writeFinallResToFile(testTrue, testFalse, mapRes, useTwoWay,
						"data/handweight/pr2-go-" + curIdx + "-" + curWeight + ".txt");
				curWeight += 0.2;
			}
			UniformRelation.weights[curIdx] = 1;
			curIdx += 2;
		}
	}

	public static void testDifferentWeightString(SerializableGraph sg, HashMap<String, HashSet<EdgeInfo>> testTrue , HashMap<String, HashSet<EdgeInfo>> testFalse,double alpha) {
		// do_is_a, hp_is_a, go_*, do_gene, go_gene, hp_gene, gene_gene
		double curWeight = 0;
		int curIdx = 6;
		boolean useTwoWay = false;
		for (int j = 0; j < 30; j++) {
			UniformRelation.weights[curIdx] = curWeight;
			HashMap<String, LinkedList<VertexWithPr>> mapRes = getAllPr(
					testTrue, sg, true, useTwoWay, alpha);
			writeFinallResToFile(testTrue, testFalse, mapRes, useTwoWay,
					"data/handweight/pr2-string-" + curIdx + "-" + curWeight + ".txt");
			curWeight += 0.2;
		}
		UniformRelation.weights[curIdx] = 1;
	}

	public static void testDifferentWeightHp(SerializableGraph sg, HashMap<String, HashSet<EdgeInfo>> testTrue , HashMap<String, HashSet<EdgeInfo>> testFalse, double alpha) {
		// do_is_a, hp_is_a, go_*, do_gene, go_gene, hp_gene, gene_gene
		double curWeight = 0;
		int curIdx = 1;
		boolean useTwoWay = false;
		for (int i = 0; i < 2; i++) {
			curWeight = 0;
			for (int j = 0; j < 30; j++) {
				UniformRelation.weights[curIdx] = curWeight;
				HashMap<String, LinkedList<VertexWithPr>> mapRes = getAllPr(
						testTrue, sg, true, useTwoWay, alpha);
				writeFinallResToFile(testTrue, testFalse, mapRes, useTwoWay,
						"data/handweight/pr2-hp-" + curIdx + "-" + curWeight + ".txt");
				curWeight += 0.2;
			}
			UniformRelation.weights[curIdx] = 1;
			curIdx += 4;
		}
	}

	private static Logger log = LoggerFactory
			.getLogger(RandomWalkWithRestartMethods.class);

	private static void writeFinallResToFile(
			HashMap<String, HashSet<EdgeInfo>> testTrue,
			HashMap<String, HashSet<EdgeInfo>> testFalse,
			HashMap<String, LinkedList<VertexWithPr>> allPr, boolean isTwoWay,
			String fileName) {
		Collection<String> res = new LinkedList<>();
		Set<Entry<String, HashSet<EdgeInfo>>> entries = testTrue.entrySet();
		for (Entry<String, HashSet<EdgeInfo>> entry : entries) {
			String key = entry.getKey(); // CUI disease
			HashSet<EdgeInfo> edge = entry.getValue(); // genes
			LinkedList<VertexWithPr> listV = allPr.get(key); // cui - rank
			double finalPro = -1;
			for (EdgeInfo e : edge) {
				LinkedList<VertexWithPr> listY = allPr.get(e.getVertex()
						.getUmlsId()); // gene - rank
				double from = -1;
				double to = -1;
				for (VertexWithPr vv : listV) {
					if (vv.getVertex().getUid() == e.getVertex().getUid()) {
						from = vv.getPr();
						break;
					}
				}
				// 平均么?
				if (isTwoWay) {
					for (VertexWithPr yy : listY) {
						if (yy.getVertex().getUmlsId().equals(key)) {
							to = yy.getPr();
							break;
						}
					}
					finalPro = (to + from) / 2;
					if (finalPro != -1) {
						res.add(key + "-" + e.getVertex() + "$" + finalPro
								+ "-1");
					}
				} else {
					finalPro = from;
					if (finalPro != -1) {
						res.add(key + "-" + e.getVertex() + "$" + finalPro
								+ "-1");
					}
				}
			}
		}
		// false
		entries = testFalse.entrySet();
		for (Entry<String, HashSet<EdgeInfo>> entry : entries) {
			String key = entry.getKey();
			HashSet<EdgeInfo> edge = entry.getValue();
			LinkedList<VertexWithPr> listV = allPr.get(key);
			double finalPro = -1;
			for (EdgeInfo e : edge) {
				LinkedList<VertexWithPr> listY = allPr.get(e.getVertex()
						.getUmlsId());
				double from = -1;
				double to = -1;
				for (VertexWithPr vv : listV) {
					if (vv.getVertex().getUid() == e.getVertex().getUid()) {
						from = vv.getPr();
						break;
					}
				}
				// 平均么?
				if (isTwoWay) {
					for (VertexWithPr yy : listY) {
						if (yy.getVertex().getUmlsId().equals(key)) {
							to = yy.getPr();
							break;
						}
					}
					finalPro = (to + from) / 2;
					if (finalPro != -1) {
						res.add(key + "-" + e.getVertex() + "$" + finalPro + "-0");
					}
				}else{
					finalPro = from;
					res.add(key + "-" + e.getVertex() + "$" + finalPro + "-0");
				}
			}
		}
		FileHelper.writeFile(fileName, res);
	}

	private static HashMap<String, LinkedList<VertexWithPr>> getAllPr(
			HashMap<String, HashSet<EdgeInfo>> testmap, SerializableGraph sg,
			boolean useWeight, boolean isTwoWay, double alpha ) {
		Set<String> keys = testmap.keySet();
		Collection<HashSet<EdgeInfo>> values = testmap.values();
		int counter = 0;
		HashMap<String, LinkedList<VertexWithPr>> maps = new HashMap<>();
		for (String key : keys) {
			counter += 1;
			LinkedList<VertexWithPr> res = getRadomWalkWithRestart(
					sg.getVertexByUmls(key), sg, useWeight, alpha, 1e-6);
			maps.put(key, res);
			log.debug(counter + " .....");
		}
		// 只算单点的
		if (!isTwoWay) {
			return maps;
		}
		HashSet<String> allGene = new HashSet<>();
		for (HashSet<EdgeInfo> v : values) {
			for (EdgeInfo e : v) {
				allGene.add(e.getVertex().getUmlsId());
			}
		}
		for (String key : allGene) {
			LinkedList<VertexWithPr> res = getRadomWalkWithRestart(
					sg.getVertexByUmls(key), sg, useWeight, alpha, 1e-6);
			maps.put(key, res);
			counter += 1;
			log.debug(counter + " .....");
		}
		return maps;
	}

	private static LinkedList<VertexWithPr> getRadomWalkWithRestart(
			Vertex fromV, SerializableGraph sg, boolean useWeight, double zuni,
			double eps) {
		RandomWalkWithRestart spr1 = new RandomWalkWithRestart(sg, fromV);
		spr1.setZuni(zuni);
		LinkedList<VertexWithPr> vp1 = spr1.getPageRank(useWeight, 100, eps);
		return vp1;
	}

	
	
}
